package ihistoryApp.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.log.Log;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import ihistoryApp.config.RedisClient;
import ihistoryApp.dal.entity.Follow;
import ihistoryApp.dal.entity.Title;
import ihistoryApp.dal.entity.User;
import ihistoryApp.dal.mapper.*;
import ihistoryApp.request.*;
import ihistoryApp.utils.EmailUtil;
import ihistoryApp.utils.RedisKeyConstant;
import ihistoryApp.view.UserView;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Objects;

@Service
@Slf4j
public class LoginService {
    @Autowired
    private LoginRequestMapper loginRequestMapper;
    @Autowired
    private EmailUtil emailUtil;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private TitleMapper titleMapper;
    @Autowired
    private FollowMapper followMapper;
    @Autowired
    private RedisClient redisClient;

    public UserView loginRequest(LoginRequest request) {
        User user = loginRequestMapper.selectById(request.getUid());
        UserView userView = new UserView();
        BeanUtil.copyProperties(user, userView);
        if (!request.getPwd().equals(user.getPwd())) {
            userView = new UserView();
            userView.setUid(0);
            return userView;
        }
        LambdaQueryWrapper<Follow> fanCountQuery = new LambdaQueryWrapper<Follow>()
                .eq(Follow::getFan, userView.getUid())
                ;
        Long followCount = followMapper.selectCount(fanCountQuery);
        LambdaQueryWrapper<Follow> followCountQuery = new LambdaQueryWrapper<Follow>()
                .eq(Follow::getFollower, userView.getUid())
                ;
        Long fanCount = followMapper.selectCount(followCountQuery);
        userView.setFanCount(fanCount);
        userView.setFollowCount(followCount);
        if (Objects.isNull(userView.getTitleId())) {
            userView.setTitleName(" ");
            return userView;
        }
        Title title = titleMapper.selectById(userView.getTitleId());
        userView.setTitleName(title.getTitle());
        return userView;
    }

    public boolean getRegisterValidateCode(GetValidateCodeRequest request) {
        // 1.校验; redisKey = REGISTER_VALIDATE_CODE + ${email}
        if (!request.getEmail().contains("@")) {
            throw new RuntimeException("邮箱格式错误");
        }
        String redisKey = EmailUtil.genRedisValidateCode(request);
//        if (stringRedisTemplate.hasKey(redisKey)) {
//            throw new RuntimeException("一分钟内不能多次发送验证码!");
//        }
        // 2.生成8位验证码
        StringBuilder validateCode = new StringBuilder();
        for (int i = 1; i <= 8; i++) {
            validateCode.append(RandomUtil.randomChar());
        }
        // 3.验证码存入redis-60s
        redisClient.set(redisKey, validateCode.toString(), 60000L);
        log.info("存入验证码:{}, after:{}", validateCode, redisClient.get(redisKey));
        MailRequest mailRequest = new MailRequest();
        mailRequest.setEmail(request.getEmail());
        mailRequest.setSubject("注册");
        mailRequest.setText(validateCode.toString());
        // 4.发邮件
        emailUtil.sendSimpleMail(mailRequest);
        return true;
    }

    public Long register(RegisterRequest request) {
        // 1.校验验证码
        String redisKey = EmailUtil.genRedisValidateCode(new GetValidateCodeRequest(request.getEmail()));
        String validateCode = redisClient.get(redisKey);
        log.info("验证码:{}",validateCode);
        if (StringUtils.isBlank(validateCode) || !validateCode.equals(request.getValidateCode())) {
            return 1L; //验证码错误
        }
        // 2.accountName是否超过限制
        if (request.getNickName().length() > 20) {
            return 2L; //用户昵称不能超过20个字符
        }
        // 3.邮箱是否重复
        User accountEntity = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getEmail, request.getEmail()));
        if (Objects.nonNull(accountEntity)) {
            return 3L; //邮箱已经被注册!
        }
        // 2.注册
        accountEntity = User.builder()
                .email(request.getEmail())
                .pwd(request.getPwd())
                .nickName(request.getNickName())
                .sex(request.getSex())
                .age(Integer.valueOf(request.getAge()))
                .build();
        userMapper.insert(accountEntity);
        return accountEntity.getUid();
    }

    public Long updatePassword(UpdatePasswordRequest request) {
        if(userMapper.selectById(request.getUid())==null){return 0L;}
        String redisKey = EmailUtil.genRedisUpdatePwdValidateCode(new GetValidateCodeRequest(request.getEmail()));
        String validateCode = redisClient.get(redisKey);
        if (StringUtils.isBlank(validateCode) || !validateCode.equals(request.getValidateCode())) {
            return 1L;
        }
        LambdaUpdateWrapper<User> userLambdaUpdateWrapper = new LambdaUpdateWrapper<User>()
                .eq(User::getEmail, request.getEmail())
                .set(User::getPwd, request.getPassword())
                ;
        userMapper.update(null, userLambdaUpdateWrapper);
        return 2L;
    }

    public boolean getUpdatePwdValidateCode(GetValidateCodeRequest request) {
        // 1.校验; redisKey = REGISTER_VALIDATE_CODE + ${email}
        if (!request.getEmail().contains("@")) {
            throw new RuntimeException("邮箱格式错误");
        }
        String redisKey = EmailUtil.genRedisUpdatePwdValidateCode(request);
        if (redisClient.isExist(redisKey)) {
            throw new RuntimeException("一分钟内不能多次发送验证码!");
        }
        // 2.生成8位验证码
        StringBuilder validateCode = new StringBuilder();
        for (int i = 1; i <= 8; i++) {
            validateCode.append(RandomUtil.randomChar());
        }
        // 3.验证码存入redis-60s
        redisClient.set(redisKey, validateCode.toString(), 60000L);
        MailRequest mailRequest = new MailRequest();
        mailRequest.setEmail(request.getEmail());
        mailRequest.setSubject("密码更新验证码");
        mailRequest.setText(validateCode.toString());
        // 4.发邮件
        emailUtil.sendSimpleMail(mailRequest);
        return true;
    }

    public UserView getUserInfo(GetUserInfoRequest request) {
        User user = userMapper.selectById(request.getUid());
        UserView userView = new UserView();
        BeanUtil.copyProperties(user, userView);
        LambdaQueryWrapper<Follow> followLambdaQueryWrapper = new LambdaQueryWrapper<Follow>()
                .eq(Follow::getFan, request.getUid())
                ;
        Long followCnt = followMapper.selectCount(followLambdaQueryWrapper);
        LambdaQueryWrapper<Follow> fanLambdaQueryWrapper = new LambdaQueryWrapper<Follow>()
                .eq(Follow::getFollower, request.getUid())
                ;
        Long fanCount = followMapper.selectCount(fanLambdaQueryWrapper);
        userView.setFollowCount(followCnt);
        userView.setFanCount(fanCount);
        Title title = titleMapper.selectById(user.getTitleId());
        if (Objects.nonNull(title)) {
        userView.setTitleName(title.getTitle());
        }
        LambdaQueryWrapper<Follow> followQuery = new LambdaQueryWrapper<Follow>()
                .eq(Follow::getFan, request.getNowUid())
                .eq(Follow::getFollower, request.getUid())
                ;
        Long count = followMapper.selectCount(followQuery);
        userView.setIsFollow(count > 0);
        return userView;
    }
    public Boolean updateUserInfo(UpdateUserInfoRequest request) {
        LambdaUpdateWrapper<User> userLambdaUpdateWrapper = new LambdaUpdateWrapper<User>()
                .eq(User::getUid, request.getUid())
                .set(User::getNickName, request.getNickName())
                .set(User::getSex,request.getSex())
                .set(User::getAge,request.getAge())
                ;
        userMapper.update(null, userLambdaUpdateWrapper);
        return true;
    }

}
